/*
	usteve

	socket

  	FILE NAME:
  
  		socket.h
  
  	DESCRIPTION:
		
		A socket class. This is aimed towards an FPS and thus, uses UDP.

  	MODIFICATION HISTORY:
  
  		20-DEC-2008 Phillip Napieralski - Wrote the code 
*/

#pragma comment(lib,"WSOCK32.lib") /* include winsock library */


#include <winsock2.h>
#include <windows.h>

#include <stdlib.h>
#include <string>
#include <sstream>

#define DATA_SIZE 512 /* string length to send */
#define DEFAULT_PORT 6105

class Socket
{
private:
	SOCKET socketDesc;
	sockaddr_in target;
	sockaddr_in any;

public:
	void bindToPort( short port = DEFAULT_PORT );
	void init();
	void setTarget( char* ip, short port = DEFAULT_PORT );
	int sendData( char* buff, int flags = 0 );
	int receiveData( char* buff, int flags = 0 );
	
	/* Wait for or send a registration message (simply "ShoeRegister") */
	int waitForRegistration( int flags = 0 );
	int sendRegistration( int flags = 0 );

	Socket() 
	{ 
		init(); 
	}

	~Socket()
	{ 
		closesocket(socketDesc);
		WSACleanup(); 
	}
};

void Socket::bindToPort( short port )
{
	sockaddr_in addr;

	memset(&addr, 0, sizeof(sockaddr_in) );

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = INADDR_ANY;
	addr.sin_port = htons(port);

	if( bind( socketDesc, (sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR )
	{
		throw "Could not bind to port!";
	}
}

void Socket::init()
{
	WSADATA info;
	if( WSAStartup(MAKEWORD(2,0), &info) )
	{
		throw "Could not start WSA!";
	}

	/* Start a UDP socket */
	socketDesc = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

	if( socketDesc == INVALID_SOCKET ) 
	{
		throw "INVALID_SOCKET!";
	}

	target.sin_family = AF_INET;
	target.sin_addr.s_addr = INADDR_ANY;
}

void Socket::setTarget( char* ip, short port )
{
	LPHOSTENT ptrh;
	
	target.sin_addr.s_addr = inet_addr(ip);

	if( target.sin_addr.s_addr == INADDR_NONE )
	{
		ptrh = gethostbyname( ip );
		if( ptrh == NULL )
		{
			throw "Invalid IP specified!";
		}
		else	
			target.sin_addr.s_addr = ((LPIN_ADDR)ptrh->h_addr)->s_addr;
	}

	if( port > 0 )
		target.sin_port = htons((u_short) port );
	else
		throw "Bad port number!";

}

int Socket::receiveData( char buff[DATA_SIZE], int flags )
{
	memset( buff, '\0', sizeof( buff ) );
	recvfrom( socketDesc, buff, DATA_SIZE, flags, 0, 0 );
	return 0;
}

int Socket::sendData( char *buff, int flags )
{
	return sendto( socketDesc, 
				buff, 
				strlen( buff ), 
				flags,
				(struct sockaddr *) &target,
				sizeof( target ) );
}

int Socket::waitForRegistration( int flags )
{
	char buff[DATA_SIZE];
	int len = sizeof( target );

	memset( buff, '\0', sizeof( buff ) );
	recvfrom( socketDesc, buff, DATA_SIZE, flags, (sockaddr *) &target, &len );

	if( strcmp(buff, "SockRegister" ) == 1)
	{
		cout << "Registration failed!" << endl;
		return 1; /* error */
	}

	return 0; /* no error! */ 
}

int Socket::sendRegistration( int flags )
{
	char buff[] = "SockRegister";

	return sendto( socketDesc,
		buff,
		strlen( buff ),
		flags,
		(struct sockaddr *) &target,
		sizeof( target ) );
}

